<?php

namespace Agi\Config;


/**
 * 数据库配置
 *
 * 为啥SplEnum不是标准库……
 *
 * @package Agi\Config
 * @author  Janpoem created at 2015/3/11 6:40
 *
 * @property string $name          数据库名称
 * @property int    $type          数据库的类型值表示，$dbConf->type === Db::MYSQL_VALUE
 * @property string $adapter       驱动，并不提供预设的模式，由使用者自行取决
 * @property string $host          主机，针对需要host类型的数据库配置
 * @property int    $port          端口，host所需
 * @property string $path          路径，针对如sqlite，基于路径访问的数据库
 * @property string $username      用户名
 * @property string $password      密码
 * @property string $db            数据库
 * @property string $prefix        表前缀
 * @property string $charset       连接字符串
 * @property bool   $isPdo         是否PDO驱动
 * @property bool   $isNative      是否原生驱动
 * @property array  $readClusters  读写分离
 */
class Db extends Config
{

    /** 未知数据库名 */
    const UNKNOWN_NAME = 'unknown';

    /** MySQL 名称 */
    const MYSQL_NAME = 'mysql';
    /** Oracle 名称 */
    const ORACLE_NAME = 'oracle';
    /** PGSQL 名称 */
    const PGSQL_NAME = 'pgsql';
    /** SQL Server 名称 */
    const SQLSRV_NAME = 'sqlsrv';
    /** SQLite 名称 */
    const SQLITE_NAME = 'sqlite';

    /** MySQL 数据库标识 */
    const MYSQL_VALUE = 0;
    /** Oracle 数据库标识 */
    const ORACLE_VALUE = 1;
    /** PGSQL_VALUE 数据库标识 */
    const PGSQL_VALUE = 2;
    /** SQL Server 数据库标识 */
    const SQLSRV_VALUE = 3;
    /** SQLite 数据库标识 */
    const SQLITE_VALUE = 4;

    /** PDO 驱动的个位值 */
    const PDO_VALUE = 8;
    /** 原生驱动的个位值 */
    const NAT_VALUE = 9;

    // @todo 需要添加其他数据库，MongoDB，可以额外添加一个类来实现

    // 常用的Adapter名称，这些名称不具备任何特别的含义，只为了提供一种识别，并不做严格检查
    ////////////////// MySQL //////////////////
    /** PDO_MYSQL */
    const MYSQL_PDO = 8;
    /** MySQLi */
    const MYSQL_NAT = 9;
    /** MySQL PHP最早的驱动库，mysql_connect */
    const MYSQL_PHP = 7;

    ////////////////// Oracle //////////////////
    /** PDO_ORI */
    const ORACLE_PDO = 18;
    /** Oracle 原生库 */
    const ORACLE_NAT = 19;

    ////////////////// PGSQL_VALUE //////////////////
    /** PGO_PGSQL */
    const PGSQL_PDO = 28;
    /** PGSQL_VALUE 原生库 */
    const PGSQL_NAT = 29;

    ////////////////// SQL Server //////////////////
    /** PGO_SQLSRV */
    const SQLSRV_PDO = 38;
    /** SQL Server 原生库 */
    const SQLSRV_NAT = 39;

    ////////////////// SQL Lite //////////////////
    /** PDO_SQLITE */
    const SQLITE_PDO = 48;
    /** SQLite 原生库 */
    const SQLITE_NAT = 49;

    /** @var string 数据库配置前缀 */
    protected static $namespace = 'db';

    /** @var array 数据库名 */
    protected static $names = array(
        self::MYSQL_VALUE  => self::MYSQL_NAME,
        self::ORACLE_VALUE => self::ORACLE_NAME,
        self::PGSQL_VALUE  => self::PGSQL_NAME,
        self::SQLSRV_VALUE => self::SQLSRV_NAME,
        self::SQLITE_VALUE => self::SQLITE_NAME,
    );

//    /** @var array 数据库规格 */
//    private static $configs = array(
//        self::MYSQL_VALUE => array(
//            'adapter'  => self::MYSQL_PDO,
//            'host'     => '127.0.0.1',
//            'port'     => 3306,
//            'username' => null,
//            'password' => null,
//            'db'       => null,
//            'prefix'   => null,
//            'charset'  => 'utf8',
//        ),
//        // @todo 需要添加其他的数据库配置的标准规格
//    );

    protected $type = -1;

    protected $adapter = -1;

    /**
     * 注册自定义数据库
     *
     * <code>
     * // 定义一些常量
     * define('MYDB_NAME', 'my-db');
     * define('MYDB_VALUE', 8);
     * define('MYDB_PDO', 80 + Db::PDO_VALUE);
     *
     * // 注册一个数据库
     * if (Db::register(MYDB_VALUE, MYDB_NAME)) {
     *     Db::define('my-db', array(
     *         'adapter' => MYDB_PDO,
     *         'host' => 123,
     *         'any' => '123',
     *     ));
     *     // 取回这个数据库配置
     *     $conf = Db::get('my-db');
     *     // 检查一下
     *     var_dump(123, $conf->host);
     *     var_dump('123', $conf->any);
     *     var_dump(MYDB_NAME, $conf->name);
     *     var_dump(MYDB_VALUE, $conf->type);
     *     var_dump(true, $conf->isPdo);
     * }
     * </code>
     *
     * @param int    $value 基础值
     * @param string $name  名称
     *
     * @return bool 是否注册成功
     */
    public static function register($value, $name)
    {
        if (!isset(self::$names[$value])) {
            self::$names[$value] = $name;
            return true;
        }
        return false;
    }

    /**
     * 数据过滤
     *
     * @param array $data
     *
     * @return array
     * @throws \Exception
     */
    public function filterData(array $data)
    {
        if (!isset($data['adapter']))
            throw new \Exception('un-define db adapter!');

        list($this->type, $this->adapter) = $this->parseAdapter($data['adapter']);

        $data['type'] = $this->type;
        $data['name'] = isset(self::$names[$this->type]) ? self::$names[$this->type] : self::UNKNOWN_NAME;
        $data['isPdo'] = $this->adapter === self::PDO_VALUE;
        $data['isNative'] = $this->adapter === self::NAT_VALUE;

        // @todo 这里要增加过滤读写分离的配置，要去掉无效的服务器配置
        // @todo 过滤PDO的配置数据
        // 不在对数据库的规格进行限制
//        if (isset(self::$configs[$this->type]))
//            $data += self::$configs[$this->type];

        return $data;
    }

    /**
     * 解析adapter的值
     *
     * @param int $adapter
     *
     * @return array
     */
    public function parseAdapter($adapter)
    {
        return array(intval($adapter / 10), $adapter % 10);
    }
}
